package com.xgy.ordering.service;

import lombok.extern.slf4j.Slf4j;
import com.xgy.ordering.entity.Order;
import com.xgy.ordering.collection.SmartList;
import com.xgy.ordering.dto.TestResults;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
public class PerformanceService {

    /**
     * 执行性能测试
     */
    public TestResults executePerformanceTest(int dataSize, String testType, int iterations) {
        TestResults results = new TestResults();
        results.setDataSize(dataSize);
        results.setTestType(testType);
        results.setIterations(iterations);

        List<Double> arrayListTimes = new ArrayList<>();
        List<Double> linkedListTimes = new ArrayList<>();
        List<Double> smartListTimes = new ArrayList<>();

        for (int i = 0; i < iterations; i++) {
            try {
                // 为每次迭代生成新的测试数据
                List<Order> testData = generateTestData(dataSize);

                double arrayListTime, linkedListTime, smartListTime;

                // 根据测试类型执行不同的测试逻辑
                switch (testType) {
                    case "insert":
                        // 插入性能测试
                        arrayListTime = testInsertPerformance(new ArrayList<>(), new ArrayList<>(testData));
                        linkedListTime = testInsertPerformance(new LinkedList<>(), new ArrayList<>(testData));
                        smartListTime = testInsertPerformance(new SmartList<>(), new ArrayList<>(testData));
                        break;
                    case "access":
                        // 随机访问性能测试
                        arrayListTime = testAccessPerformance(new ArrayList<>(testData));
                        linkedListTime = testAccessPerformance(new LinkedList<>(testData));
                        smartListTime = testAccessPerformance(new SmartList<>(testData));
                        break;
                    case "mixed":
                        // 混合操作性能测试
                        arrayListTime = testMixedPerformance(new ArrayList<>(), new ArrayList<>(testData));
                        linkedListTime = testMixedPerformance(new LinkedList<>(), new ArrayList<>(testData));
                        smartListTime = testMixedPerformance(new SmartList<>(), new ArrayList<>(testData));
                        break;
                    default:
                        // 默认使用插入测试
                        arrayListTime = testInsertPerformance(new ArrayList<>(), new ArrayList<>(testData));
                        linkedListTime = testInsertPerformance(new LinkedList<>(), new ArrayList<>(testData));
                        smartListTime = testInsertPerformance(new SmartList<>(), new ArrayList<>(testData));
                        break;
                }

                arrayListTimes.add(arrayListTime);
                linkedListTimes.add(linkedListTime);
                smartListTimes.add(smartListTime);

                // 添加更长的GC间隔
                System.gc();
                try { Thread.sleep(100); } catch (InterruptedException e) {}

            } catch (Exception e) {
                // 记录错误但继续测试
                log.error("测试迭代 {} 失败: {}", i, e.getMessage());
                // 添加默认值以保持结果一致性
                arrayListTimes.add(0.0);
                linkedListTimes.add(0.0);
                smartListTimes.add(0.0);
            }
        }

        results.setArrayListTimes(arrayListTimes);
        results.setLinkedListTimes(linkedListTimes);
        results.setSmartListTimes(smartListTimes);

        return results;
    }

    /**
     * 更安全的插入性能测试方法
     */
    private double testInsertPerformance(List<Order> targetList, List<Order> sourceData) {
        // 预热
        if (targetList instanceof SmartList) {
            ((SmartList<Order>) targetList).getStorageInfo(); // 初始化
        }

        long startTime = System.nanoTime();

        try {
            // 分批插入以减少内存压力
            int batchSize = Math.max(1000, sourceData.size() / 10);
            for (int i = 0; i < sourceData.size(); i += batchSize) {
                int end = Math.min(i + batchSize, sourceData.size());
                for (int j = i; j < end; j++) {
                    targetList.add(sourceData.get(j));
                }
            }
        } catch (Exception e) {
            log.error("插入性能测试出错: {}", e.getMessage());
            // 返回一个较大的值表示失败
            return Long.MAX_VALUE / 1000;
        }

        long endTime = System.nanoTime();
        long durationNs = endTime - startTime;
        // 返回毫秒单位，但保留更高精度（使用double避免小规模测试显示为0ms）
        return (double) durationNs / 1_000_000.0;
    }

    /**
     * 随机访问性能测试方法
     */
    private double testAccessPerformance(List<Order> targetList) {
        if (targetList.isEmpty()) {
            return 0.0;
        }

        Random random = new Random();
        long startTime = System.nanoTime();

        try {
            // 执行多次随机访问
            int accessCount = Math.min(targetList.size(), 10000);
            for (int i = 0; i < accessCount; i++) {
                int index = random.nextInt(targetList.size());
                Order order = targetList.get(index);
                // 确保访问不被优化掉
                if (order == null) {
                    throw new RuntimeException("访问到空元素");
                }
            }
        } catch (Exception e) {
            log.error("随机访问性能测试出错: {}", e.getMessage());
            return Long.MAX_VALUE / 1000;
        }

        long endTime = System.nanoTime();
        long durationNs = endTime - startTime;
        // 返回毫秒单位，但保留更高精度（使用double避免小规模测试显示为0ms）
        return (double) durationNs / 1_000_000.0;
    }

    /**
     * 混合操作性能测试方法
     */
    private double testMixedPerformance(List<Order> targetList, List<Order> sourceData) {
        // 预热
        if (targetList instanceof SmartList) {
            ((SmartList<Order>) targetList).getStorageInfo(); // 初始化
        }

        long startTime = System.nanoTime();

        try {
            Random random = new Random();
            // 增加操作次数，确保有足够的测试时间
            int operationCount = Math.max(1000, Math.min(5000, sourceData.size()));
            
            // 先插入一些数据，确保列表不为空
            int initialInsertCount = Math.min(100, sourceData.size());
            for (int i = 0; i < initialInsertCount; i++) {
                targetList.add(sourceData.get(i));
            }
            
            for (int i = 0; i < operationCount; i++) {
                int operation = random.nextInt(3);
                switch (operation) {
                    case 0: // 插入
                        if (i < sourceData.size()) {
                            targetList.add(sourceData.get(i));
                        }
                        break;
                    case 1: // 访问
                        if (!targetList.isEmpty()) {
                            int index = random.nextInt(targetList.size());
                            Order order = targetList.get(index);
                            // 确保访问不被优化掉
                            if (order == null) {
                                throw new RuntimeException("访问到空元素");
                            }
                        }
                        break;
                    case 2: // 删除
                        if (!targetList.isEmpty()) {
                            int index = random.nextInt(targetList.size());
                            targetList.remove(index);
                        }
                        break;
                }
            }
        } catch (Exception e) {
            log.error("混合性能测试出错: {}", e.getMessage());
            return Long.MAX_VALUE / 1000;
        }

        long endTime = System.nanoTime();
        long durationNs = endTime - startTime;
        // 返回毫秒单位，但保留更高精度（使用double避免小规模测试显示为0ms）
        return (double) durationNs / 1_000_000.0;
    }

    /**
     * 生成测试数据 - 优化版本
     */
    private List<Order> generateTestData(int count) {
        List<Order> testData = new ArrayList<>(count);
        Random random = new Random();
        String[] customers = {"张三", "李四", "王五", "赵六", "钱七", "孙八", "周九", "吴十"};
        String[] foods = {"红烧肉", "宫保鸡丁", "鱼香肉丝", "麻婆豆腐", "回锅肉", "水煮鱼", "糖醋里脊", "京酱肉丝"};
        Order.OrderStatus[] statuses = Order.OrderStatus.values();

        // 使用唯一ID生成器避免重复
        long baseTimestamp = System.currentTimeMillis();
        
        for (int i = 0; i < count; i++) {
            String customer = customers[random.nextInt(customers.length)];
            String food = foods[random.nextInt(foods.length)];
            double amount = 20 + random.nextDouble() * 100;
            Order.OrderStatus status = statuses[random.nextInt(statuses.length)];

            // 使用唯一ID：基础时间戳 + 索引 + 随机数
            String uniqueId = String.format("ORD%d_%d_%d", baseTimestamp, i, random.nextInt(1000));
            testData.add(createOrder(uniqueId, customer, amount, food, status));
        }

        return testData;
    }

    private Order createOrder(String id, String customer, double amount, String food, Order.OrderStatus status) {
        return new Order(id, customer, amount, food, LocalDateTime.now(), status);
    }

    /**
     * 获取对比数据 - 执行真实性能测试
     */
    public Map<String, Object> getComparisonData() {
        Map<String, Object> data = new HashMap<>();

        // 测试数据规模（调整为更合理的范围）
        int[] sizes = {1000, 5000, 10000, 20000, 50000};
        Map<String, List<Double>> performanceData = new HashMap<>();
        
        List<Double> arrayListTimes = new ArrayList<>();
        List<Double> linkedListTimes = new ArrayList<>();
        List<Double> smartListTimes = new ArrayList<>();

        // 对每个数据规模执行真实测试
        for (int size : sizes) {
            try {
                log.info("开始执行数据规模为 {} 的性能测试", size);
                
                // 执行插入性能测试（3次迭代取平均值）
                TestResults results = executePerformanceTest(size, "insert", 3);
                
                // 计算平均时间
                double arrayListAvg = results.getArrayListTimes().stream().mapToDouble(Double::doubleValue).average().orElse(0);
                double linkedListAvg = results.getLinkedListTimes().stream().mapToDouble(Double::doubleValue).average().orElse(0);
                double smartListAvg = results.getSmartListTimes().stream().mapToDouble(Double::doubleValue).average().orElse(0);
                
                arrayListTimes.add(arrayListAvg);
                linkedListTimes.add(linkedListAvg);
                smartListTimes.add(smartListAvg);
                
                log.info("数据规模 {} 测试完成: ArrayList={}ms, LinkedList={}ms, SmartList={}ms", 
                        size, arrayListAvg, linkedListAvg, smartListAvg);
                        
                // 测试间隔，避免连续测试导致JVM不稳定
                Thread.sleep(500);
                
            } catch (Exception e) {
                log.error("数据规模 {} 的性能测试失败: {}", size, e.getMessage());
                // 添加默认值保持数据结构一致
                arrayListTimes.add(0.0);
                linkedListTimes.add(0.0);
                smartListTimes.add(0.0);
            }
        }

        performanceData.put("ArrayList", arrayListTimes);
        performanceData.put("LinkedList", linkedListTimes);
        performanceData.put("SmartList", smartListTimes);

        data.put("sizes", sizes);
        data.put("performance", performanceData);
        data.put("note", "此为真实性能测试数据，测试环境：" + System.getProperty("java.version") + 
                ", 内存：" + Runtime.getRuntime().maxMemory() / 1024 / 1024 + "MB");
        data.put("timestamp", System.currentTimeMillis());

        return data;
    }
}